
// UstavMFCServerDlg.cpp : implementation file
//
#include "stdafx.h"
#include "UstavMFCServer.h"
#include "UstavMFCServerDlg.h"
#include "afxdialogex.h"

#include <string> 

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CUstavMFCServerDlg dialog
CUstavMFCServerDlg::CUstavMFCServerDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CUstavMFCServerDlg::IDD, pParent)
    , m_yaw(0)
    , m_pitch(0)
    , m_roll(0)
    , m_heading(0)
    , m_latitude(0)
    , m_longitude(0)
    , m_altitude(0)
    , m_airSpeed(0)
    , m_groundSpeed(0)
    , m_consumption(0)
    , m_batteryLife(0)
    , m_health(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CUstavMFCServerDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_CHECK_LOCK_PORT, m_checkLock_port);
    DDX_Control(pDX, IDC_CHECK_LOCK_BAUD, m_checkLock_baud);
    DDX_Control(pDX, IDC_CHECK_LOCK_STOP_BITS, m_checkLock_stopBits);
    DDX_Control(pDX, IDC_CHECK_LOCK_FLOW_CONTROL, m_checkLock_flowControl);
    DDX_Control(pDX, IDC_CHECK_LOCK_OVERLAPPED, m_checkLock_overlapped);
    DDX_Control(pDX, IDC_CHECK_LOCK_PARITY, m_checkLock_parity);
    DDX_Control(pDX, IDC_CHECK_LOCK_DATA_BITS, m_checkLock_dataBits);
    DDX_Control(pDX, IDC_COMBO_PORT, m_cb_port);
    DDX_Control(pDX, IDC_COMBO_BAUD, m_cb_baud);
    DDX_Control(pDX, IDC_COMBO_PARITY, m_cb_parity);
    DDX_Control(pDX, IDC_COMBO_DATA_BITS, m_cb_dataBits);
    DDX_Control(pDX, IDC_COMBO_STOP_BITS, m_cb_stopBits);
    DDX_Control(pDX, IDC_COMBO_FLOW_CONTROL, m_cb_flowControl);
    DDX_Control(pDX, IDC_CHECK_OVERLAPPED, m_b_overlapped);
    DDX_Control(pDX, IDC_EDIT_LOG, m_logBox);
    DDX_Control(pDX, IDC_BUTTON_OPEN_CLOSE_PORT, m_b_openClosePort);
    DDX_Control(pDX, IDC_BUTTON_SEND_DATA, m_b_sendData);
    DDX_Control(pDX, IDC_BUTTON_SEND_STATUS, m_b_sendStatus);
    // USData
    DDX_Text(pDX, IDC_EDIT_YAW, m_yaw);
    DDV_MinMaxInt(pDX, m_yaw, US_DATA_YAW_MIN, US_DATA_YAW_MAX);
    DDX_Text(pDX, IDC_EDIT_PITCH, m_pitch);
    DDV_MinMaxInt(pDX, m_pitch, US_DATA_PITCH_MIN, US_DATA_PITCH_MAX);
    DDX_Text(pDX, IDC_EDIT_ROLL, m_roll);
    DDV_MinMaxInt(pDX, m_roll, US_DATA_ROLL_MIN, US_DATA_ROLL_MAX);
    DDX_Text(pDX, IDC_EDIT_HEADING, m_heading);
    DDV_MinMaxInt(pDX, m_heading, US_DATA_HEADING_MIN, US_DATA_HEADING_MAX);
    DDX_Text(pDX, IDC_EDIT_POS_LATITUDE, m_latitude);
    DDV_MinMaxDouble(pDX, m_latitude, US_DATA_LATITUDE_MIN, US_DATA_LATITUDE_MAX);
    DDX_Text(pDX, IDC_EDIT_LONGITUDE, m_longitude);
    DDV_MinMaxDouble(pDX, m_longitude, US_DATA_LONGITUDE_MIN, US_DATA_LONGITUDE_MAX);
    DDX_Text(pDX, IDC_EDIT_ALTITUDE, m_altitude);
    DDV_MinMaxFloat(pDX, m_altitude, US_DATA_ALTITUDE_MIN, US_DATA_ALTITUDE_MAX);
    DDX_Text(pDX, IDC_EDIT_AIRSPEED, m_airSpeed);
    DDV_MinMaxFloat(pDX, m_airSpeed, US_DATA_AIRSPEED_MIN, US_DATA_AIRSPEED_MAX);
    DDX_Text(pDX, IDC_EDIT_GROUND_SPEED, m_groundSpeed);
    DDV_MinMaxFloat(pDX, m_groundSpeed, US_DATA_GROUNDSPEED_MIN, US_DATA_GROUNDSPEED_MAX);
    // USStatus
    DDX_Text(pDX, IDC_EDIT_CONSUMPTION, m_consumption);
    DDV_MinMaxInt(pDX, m_consumption, US_STATUS_CONSUMPTION_MIN, US_STATUS_CONSUMPTION_MAX);
    DDX_Text(pDX, IDC_EDIT_BATTERY_LIFE, m_batteryLife);
    DDV_MinMaxInt(pDX, m_batteryLife, US_STATUS_BATTERYLIFE_MIN, US_STATUS_BATTERYLIFE_MAX);
    DDX_Text(pDX, IDC_EDIT_UAV_HEALTH, m_health);
    DDV_MinMaxInt(pDX, m_health, US_STATUS_HEALTH_MIN, US_STATUS_HEALTH_MAX);
}

BEGIN_MESSAGE_MAP(CUstavMFCServerDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_CHECK_LOCK_PORT, &CUstavMFCServerDlg::OnBnClickedCheckLockPort)
    ON_BN_CLICKED(IDC_CHECK_LOCK_BAUD, &CUstavMFCServerDlg::OnBnClickedCheckLockBaud)
    ON_BN_CLICKED(IDC_CHECK_LOCK_PARITY, &CUstavMFCServerDlg::OnBnClickedCheckLockParity)
    ON_BN_CLICKED(IDC_CHECK_LOCK_DATA_BITS, &CUstavMFCServerDlg::OnBnClickedCheckLockDataBits)
    ON_BN_CLICKED(IDC_CHECK_LOCK_STOP_BITS, &CUstavMFCServerDlg::OnBnClickedCheckLockStopBits)
    ON_BN_CLICKED(IDC_CHECK_LOCK_FLOW_CONTROL, &CUstavMFCServerDlg::OnBnClickedCheckLockFlowControl)
    ON_BN_CLICKED(IDC_CHECK_LOCK_OVERLAPPED, &CUstavMFCServerDlg::OnBnClickedCheckLockOverlapped)
    ON_BN_CLICKED(IDC_BUTTON_OPEN_CLOSE_PORT, &CUstavMFCServerDlg::OnBnClickedButtonOpenClosePort)
    ON_BN_CLICKED(IDC_BUTTON_SEND_DATA, &CUstavMFCServerDlg::OnBnClickedButtonSendData)
    ON_BN_CLICKED(IDC_BUTTON_SEND_STATUS, &CUstavMFCServerDlg::OnBnClickedButtonSendStatus)
END_MESSAGE_MAP()


// CUstavMFCServerDlg message handlers

BOOL CUstavMFCServerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon


    //m_ptrUsData = new USData();

	// Extra initialization here
    m_checkLock_port.SetCheck(FALSE);
    m_checkLock_baud.SetCheck(FALSE);
    m_checkLock_stopBits.SetCheck(TRUE);
    m_checkLock_flowControl.SetCheck(TRUE);
    m_checkLock_overlapped.SetCheck(TRUE);
    m_checkLock_parity.SetCheck(TRUE);
    m_checkLock_dataBits.SetCheck(TRUE);

    // Fill in combo boxes
    InitPorts();
    InitBauds();
    InitParities();
    InitDataBits();
    InitStopBits();
    InitFlowControls();
    
    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CUstavMFCServerDlg::InitPorts()
{
    // Get Available Ports and fill in ports combobox
    CString portName;
    for (int portNumber = 1; portNumber < 256; ++portNumber)
    {
        if (portNumber < 10) 
        {
            portName.Format(_T("COM%d"), portNumber);
        }
        else
        {
            portName.Format(_T("\\\\.\\COM%d"), portNumber);
        }

        HANDLE hFile = ::CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
             OPEN_EXISTING, 0, NULL);
        
        if (hFile != INVALID_HANDLE_VALUE)
            m_cb_port.AddString(portName);
        else
        {
            DWORD err = GetLastError();
            if (err == ERROR_ACCESS_DENIED)
            {
                LogMessage(_T("Acces denied for: ") + portName);
            }
            else if (err == ERROR_SHARING_VIOLATION)
            {
                LogMessage(_T("Error Sharing violation for: ") + portName);
            }
        }
        CloseHandle(hFile);
    }

    m_cb_port.SetCurSel(0);
}

void CUstavMFCServerDlg::InitBauds()
{
    // Fill in baud combobox
    m_cb_baud.AddString("1200");
    m_cb_baud.AddString("2400");
    m_cb_baud.AddString("4800");
    m_cb_baud.AddString("9600");
    m_cb_baud.AddString("14400");
    m_cb_baud.AddString("19200");
    m_cb_baud.AddString("38400");
    m_cb_baud.AddString("57600");
    m_cb_baud.AddString("115200");

    m_cb_baud.SetCurSel(7);
}

void CUstavMFCServerDlg::InitParities()
{
    // Create parity map and fill in parity combobox
    m_parityMap["No Parity"] = CSerialPort::NoParity;
    m_cb_parity.AddString("No Parity");
    m_parityMap["Odd Parity"] = CSerialPort::OddParity;
    m_cb_parity.AddString("Odd Parity");
    m_parityMap["Even Parity"] = CSerialPort::EvenParity;
    m_cb_parity.AddString("Even Parity");
    m_parityMap["Mark Parity"] = CSerialPort::MarkParity;
    m_cb_parity.AddString("Mark Parity");
    m_parityMap["Space Parity"] = CSerialPort::SpaceParity;
    m_cb_parity.AddString("Space Parity");

    m_cb_parity.SetCurSel(0);
}

void CUstavMFCServerDlg::InitDataBits()
{
    // Fill in data bits combobox
    m_cb_dataBits.AddString("5");
    m_cb_dataBits.AddString("6");
    m_cb_dataBits.AddString("7");
    m_cb_dataBits.AddString("8");
    m_cb_dataBits.AddString("9");

    m_cb_dataBits.SetCurSel(3);
}

void CUstavMFCServerDlg::InitStopBits()
{
    // Create stop bits map and fill in stop bits combobox
    m_stopBitsMap["One"] = CSerialPort::OneStopBit;
    m_cb_stopBits.AddString("One stop bit");
    m_stopBitsMap["One Point Five Stop Bits"] = CSerialPort::OnePointFiveStopBits;
    m_cb_stopBits.AddString("One Point Five Stop Bits");
    m_stopBitsMap["Two Stop Bits"] = CSerialPort::TwoStopBits;
    m_cb_stopBits.AddString("Two Stop Bits");

    m_cb_stopBits.SetCurSel(0);
}

void CUstavMFCServerDlg::InitFlowControls()
{
    // Create flow control map and fill in flow control combobox
    m_flowControlMap["No Flow Control"] = CSerialPort::NoFlowControl;
    m_cb_flowControl.AddString("No Flow Control");
    m_flowControlMap["Cts Dtr Flow Control"] = CSerialPort::CtsDtrFlowControl;
    m_cb_flowControl.AddString("Cts Rts Flow Control");
    m_flowControlMap["Cts Dtr Flow Control"] = CSerialPort::CtsRtsFlowControl;
    m_cb_flowControl.AddString("Cts Dtr Flow Control");
    m_flowControlMap["Dsr Rts Flow Control"] = CSerialPort::DsrRtsFlowControl;
    m_cb_flowControl.AddString("Dsr Rts Flow Control");
    m_flowControlMap["Dsr Dtr Flow Control"] = CSerialPort::DsrDtrFlowControl;
    m_cb_flowControl.AddString("Dsr Dtr Flow Control");
    m_flowControlMap["Xon/Xoff Flow Control"] = CSerialPort::XonXoffFlowControl;
    m_cb_flowControl.AddString("Xon/Xoff Flow Control");
    
    m_cb_flowControl.SetCurSel(0);
}

void CUstavMFCServerDlg::LogMessage(LPCTSTR pszText)
{
   // get the initial text length
   int nLength = m_logBox.GetWindowTextLength();
   // put the selection at the end of text
   m_logBox.SetSel(nLength, nLength);
   // replace the selection
   m_logBox.ReplaceSel(CString(pszText) + char(13) + char(10));
}

void CUstavMFCServerDlg::EnableLockCheckBoxes(BOOL enable=TRUE)
{
    m_checkLock_port.EnableWindow(enable);
    m_checkLock_baud.EnableWindow(enable);
    m_checkLock_stopBits.EnableWindow(enable);
    m_checkLock_flowControl.EnableWindow(enable);
    m_checkLock_overlapped.EnableWindow(enable);
    m_checkLock_parity.EnableWindow(enable);
    m_checkLock_dataBits.EnableWindow(enable);
}

void CUstavMFCServerDlg::EnableSendButtons(BOOL enable=TRUE)
{
    m_b_sendData.EnableWindow(enable);
    m_b_sendStatus.EnableWindow(enable);
}

void CUstavMFCServerDlg::OpenSerialPort()
{
    // Remember status of combo boxes and a check box
    m_enabled_port = m_cb_port.EnableWindow(FALSE);
    m_enabled_baud = m_cb_baud.EnableWindow(FALSE);
    m_enabled_parity = m_cb_parity.EnableWindow(FALSE);
    m_enabled_dataBits = m_cb_dataBits.EnableWindow(FALSE);
    m_enabled_stopBits = m_cb_stopBits.EnableWindow(FALSE);
    m_enabled_flowControl = m_cb_flowControl.EnableWindow(FALSE);
    m_enabled_overlapped = m_b_overlapped.EnableWindow(FALSE);

    // Disable lock checkboxes, Enable Sending buttons
    EnableLockCheckBoxes(FALSE);
    EnableSendButtons(TRUE);

    // PORT
    CString portString;
    m_cb_port.GetWindowText(portString);

    // BAUD
    CString baudString;
    m_cb_baud.GetWindowText(baudString);
    DWORD dwBaud = atoi(baudString);

    // PARITY
    CString parityString;
    m_cb_parity.GetWindowText(parityString);
    CSerialPort::Parity& parity = m_parityMap[parityString];
    
    // DATA BITS
    CString dataBitsString;
    m_cb_dataBits.GetWindowText(dataBitsString);
    BYTE dataBits = atoi(dataBitsString);

    // STOP BITS
    CString stopBitsString;
    m_cb_stopBits.GetWindowText(stopBitsString);
    CSerialPort::StopBits& stopBits = m_stopBitsMap[stopBitsString];

    // FLOW CONTROL
    CString flowControlString;
    m_cb_flowControl.GetWindowText(flowControlString);
    CSerialPort::FlowControl& flowControl = m_flowControlMap[flowControlString];
    
    BOOL overlapped = m_b_overlapped.GetCheck();

    m_serialPort.Open(portString, dwBaud, parity, dataBits, stopBits, flowControl, overlapped);

    // Logg    
    LogMessage(_T("Port Opened"));
}

void CUstavMFCServerDlg::CloseSerialPort()
{
    m_serialPort.Close();

    // Enable lock checkboxes, Disable Sending buttons
    EnableLockCheckBoxes(TRUE);
    EnableSendButtons(FALSE);

    // Restore status of combo boxes and a check box
    m_cb_port.EnableWindow(!m_enabled_port);
    m_cb_baud.EnableWindow(!m_enabled_baud);
    m_cb_parity.EnableWindow(!m_enabled_parity);
    m_cb_dataBits.EnableWindow(!m_enabled_dataBits);
    m_cb_stopBits.EnableWindow(!m_enabled_stopBits);
    m_cb_flowControl.EnableWindow(!m_enabled_flowControl);
    m_b_overlapped.EnableWindow(!m_enabled_overlapped);

    // Logg
    LogMessage(_T("Port Closed"));
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CUstavMFCServerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CUstavMFCServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CUstavMFCServerDlg::OnBnClickedCheckLockPort()
{
    UpdateData();
    m_cb_port.EnableWindow(!m_checkLock_port.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedCheckLockBaud()
{
    UpdateData();
    m_cb_baud.EnableWindow(!m_checkLock_baud.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedCheckLockParity()
{
    UpdateData();
    m_cb_parity.EnableWindow(!m_checkLock_parity.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedCheckLockDataBits()
{
    UpdateData();
    m_cb_dataBits.EnableWindow(!m_checkLock_dataBits.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedCheckLockStopBits()
{
    UpdateData();
    m_cb_stopBits.EnableWindow(!m_checkLock_stopBits.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedCheckLockFlowControl()
{
    UpdateData();
    m_cb_flowControl.EnableWindow(!m_checkLock_flowControl.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedCheckLockOverlapped()
{
    UpdateData();
    m_b_overlapped.EnableWindow(!m_checkLock_overlapped.GetCheck());
}

void CUstavMFCServerDlg::OnBnClickedButtonOpenClosePort()
{
    if (!UpdateData())
        return;

    // Get open/close button caption
    CString buttonText;
    m_b_openClosePort.GetWindowText(buttonText);

    if (buttonText == "Open Port")
    {
        OpenSerialPort();
        m_b_openClosePort.SetWindowText("Close Port");
    }
    else
    {
        CloseSerialPort();
        m_b_openClosePort.SetWindowText("Open Port");
    }
}

void CUstavMFCServerDlg::OnBnClickedButtonSendData()
{
    if (!UpdateData())
        return;

    // Set US_DATA sentence data
    m_UsData.SetYaw(m_yaw);
    m_UsData.SetPitch(m_pitch);
    m_UsData.SetRoll(m_roll);
    m_UsData.SetHeading(m_heading);
    m_UsData.SetLatitude(m_latitude);
    m_UsData.SetLongitude(m_longitude);
    m_UsData.SetAltitude(m_altitude);
    m_UsData.SetAirspeed(m_airSpeed);
    m_UsData.SetGroundSpeed(m_groundSpeed);

    // Generate sentence
    std::string sentence;
    m_UsData.GenerateSentence(sentence);

    // Send the sentence
    m_serialPort.Write(sentence.c_str(), sentence.size());

    // Logg it
    LogMessage(sentence.c_str());
}

void CUstavMFCServerDlg::OnBnClickedButtonSendStatus()
{
    // Check if all fields are valid
    if (!UpdateData())
        return;

    // Set US_STATUS sentence data
    m_UsStatus.SetConsumption(m_consumption);
    m_UsStatus.SetBatteryLife(m_batteryLife);
    m_UsStatus.SetHealth(m_health);

     // Generate sentence
    std::string sentence;
    m_UsStatus.GenerateSentence(sentence);

    // Send the sentence
    m_serialPort.Write(sentence.c_str(), sentence.size());

    // Logg it
    LogMessage(sentence.c_str());
}